Skip to content

Conversation

felipecsl
Copy link
Contributor

@felipecsl felipecsl commented Nov 20, 2024

Towards: FF-3567

Motivation and Context

Laying the groundwork for event ingestion and logging

Description

  • Added NamedEventQueue abstraction, to be shared between assignment, bandit and arbitrary application events.
  • Refactored EppoClient constructor to use props object pattern with optional args
  • Added SdkKeyDecoder to be used in follow up PRs

The js-server-sdk and js-client-sdk will have separate implementations for NamedEventQueue, one based on file storage and the other based on localstorage. I already have both implemented, will submit those as follow up PRs.
Event batching, uploading, etc. will be handled in follow up PRs as well.

How has this been tested?

Existing tests

private flagEvaluationDetailsBuilder(flagKey: string): FlagEvaluationDetailsBuilder {
// noinspection JSUnusedGlobalSymbols
track(event: unknown, params: Record<string, unknown>) {
this.eventQueue.push({ event, params });
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this implementation to be fleshed out in future PRs

@felipecsl felipecsl requested a review from petzel November 21, 2024 16:55
private isObfuscated = false,
) {}
constructor({
eventQueue = new ArrayBackedNamedEventQueue('events'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the named parameters.

🤔 I do NOT consider this a breaking change as users are not using this constructor directly; they are going through init. Am I misunderstanding?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's correct sir!

Copy link
Contributor Author

@felipecsl felipecsl Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to strict semver, this does require a major version bump, however, as you pointed out, since it's only used internally, it doesn't affect end users

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, was worried about this as well

let result: ContextAttributes;
if (this.isInstanceOfContextualAttributes(subjectAttributes)) {
result = subjectAttributes as ContextAttributes;
return subjectAttributes as ContextAttributes;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice - agreed

} else {
// If no logger defined, queue up the events (up to a max) to flush if a logger is later defined
this.queuedBanditEvents.push(banditEvent);
this.banditEventsQueue.push(banditEvent);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no limit anymore ya?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the limit is now encapsulated inside the logic of BoundedEventQueue#push method!

}

private logAssignment(result: FlagEvaluation) {
private maybeLogAssignment(result: FlagEvaluation) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha - true

export class BoundedEventQueue<T> {
constructor(
private readonly queue: NamedEventQueue<T>,
private readonly maxSize = MAX_EVENT_QUEUE_SIZE,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the bandit event queue above and makes sense now 👍


try {
if (this.assignmentLogger) {
this.assignmentLogger.logAssignment(event);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you considering any more major changes to the SDK behavior, such as all events getting put into a queue and processed by another worker?

Copy link
Contributor Author

@felipecsl felipecsl Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, we'll need some mechanism for batching and uploading events. I'm thinking a simple setInterval logic that uploads every N seconds, no need to overcomplicate. Thoughts?

@felipecsl felipecsl merged commit de9ae8b into main Nov 22, 2024
8 checks passed
@felipecsl felipecsl deleted the felipecsl--events branch November 22, 2024 03:07

/** A named event queue backed by an array. */
export default class ArrayBackedNamedEventQueue<T> implements NamedEventQueue<T> {
private readonly events: T[] = [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an unbounded memory-based array sounds risky. Maybe this should be limited to a certain size if/until we support spillover to disk?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see there is a separate class for limiting the size. Could we combine them to simplify and avoid the risk of someone using this class directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this class was not meant to be used directly, only internally from BoundedEventQueue via composition. I'll add a comment to make that clear, good callout

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants